﻿#include "object.hh"
#include <atomic>
#include <cstdlib>
#include <list>
#include <mutex>
#include <sstream>
#include <stdexcept>
#include <thread>
#include <unordered_map>

namespace kratos {
namespace object_system {

/**
 * 内部对象管理器，每个线程有一个独立的对象管理器.
 */
struct InternalObjectManager {
  using ObjectMap = std::unordered_map<std::uint64_t, std::shared_ptr<Object>>;
  ObjectMap alive_object_map_; ///< 活跃对象列表
  using ObjectList = std::list<std::shared_ptr<Object>>;
  std::list<std::uint64_t> dispose_id_list_; ///< 等待销毁对象列表
  std::mutex mutex_;                         ///< 锁
  std::thread::id tid_;                      ///< 当前对象管理器线程ID
  std::atomic_size_t alive_object_count_{0}; ///< 活跃对象数量
  std::atomic_size_t dispose_object_count_{0}; ///< 待销毁对象数量
  bool registered_{false};                     ///< 是否已经注册
  /**
   * 构造.
   * 
   */
  InternalObjectManager() { tid_ = std::this_thread::get_id(); }
  /**
   * 记录从其他线程发送来的销毁请求.
   * 
   * \param id 对象ID
   */
  void dispose_request_from_other_thread(std::uint64_t id) {
    std::lock_guard<std::mutex> guard(mutex_);
    dispose_id_list_.push_back(id);
  }
  /**
   * 销毁所有非活跃对象.
   * 
   */
  void do_dispose_request() {
    std::list<std::uint64_t> tmp_list;
    {
      std::lock_guard<std::mutex> guard(mutex_);
      tmp_list.swap(dispose_id_list_);
      dispose_id_list_.clear();
    }
    alive_object_count_ -= tmp_list.size();
    for (auto &id : tmp_list) {
      alive_object_map_.erase(id);
    }
    dispose_object_count_ = 0;
  }
  /**
   * 获取活跃对象数量.
   * 
   * \return 
   */
  std::size_t get_alive_object_count() { return alive_object_count_; }
  /**
   * 获取待销毁对象数量.
   * 
   * \return 
   */
  std::size_t get_dispose_object_count() { return dispose_object_count_; }
};

/**
 * 管理所有对象管理器.
 */
struct OMManager {
  using OMMap = std::unordered_map<std::thread::id, InternalObjectManager *>;
  OMMap om_map_; ///< {线程ID, 对象管理器}
  std::mutex mutex_; ///< 锁
  /**
   * 发送销毁事件.
   * 
   * \param id 对象ID
   * \param tid 线程ID 
   * \return true或false
   */
  bool send_dispose_request(std::uint64_t id, std::thread::id tid) {
    std::lock_guard<std::mutex> guard(mutex_);
    auto it = om_map_.find(tid);
    if (it == om_map_.end()) {
      return false;
    }
    it->second->dispose_request_from_other_thread(id);
    return true;
  }
  /**
   * 注册管理器.
   * 
   * \param manager 对象管理器
   */
  void register_manager(InternalObjectManager *manager) {
    if (manager->registered_) {
      return;
    }
    std::lock_guard<std::mutex> guard(mutex_);
    om_map_[manager->tid_] = manager;
    manager->registered_ = true;
  }
  /**
   * 获取活跃对象数量.
   * 
   * \return 活跃对象数量
   */
  std::size_t get_alive_object_count() {
    std::lock_guard<std::mutex> guard(mutex_);
    std::size_t count = 0;
    for (auto &om : om_map_) {
      count += om.second->get_alive_object_count();
    }
    return count;
  }
  /**
   * 获取待销毁对象数量.
   * 
   * \return 待销毁对象数量
   */
  std::size_t get_dispose_object_count() {
    std::lock_guard<std::mutex> guard(mutex_);
    std::size_t count = 0;
    for (auto &om : om_map_) {
      count += om.second->get_dispose_object_count();
    }
    return count;
  }
};
/**
 * 当前线程的对象管理器.
 */
thread_local InternalObjectManager inter_object_manager_;
/**
 * 全局管理器.
 */
OMManager om_manager_;
/**
 * 获取当前线程ID.
 * 
 * \return 当前线程ID
 */
std::thread::id get_thread_id() { return inter_object_manager_.tid_; }
/**
 * 输出调试信息.
 * 
 * \param os std::ostream
 */
void dump(std::ostream &os) {
#ifdef OBJECT_SYSTEM_DEBUG
  for (const auto &it : inter_object_manager_.alive_object_map_) {
    os << "Alllocated at(" << it.second->get_file_name() << ":"
       << it.second->get_line() << "),Type:" << it.second->type_info().name()
       << std::endl;
  }
#endif
}
/**
 * 获取活跃对象数量.
 * 
 * \return 活跃对象数量
 */
std::size_t get_alive_object_count() {
  return om_manager_.get_alive_object_count();
}
/**
 * 获取待销毁对象数量.
 * 
 * \return 待销毁对象数量
 */
std::size_t get_dispose_object_count() {
  return om_manager_.get_dispose_object_count();
}
/**
 * 添加对象.
 * 
 * \param object 对象
 * \return 对象的共享指针
 */
auto ObjectSystem::add_object(Object *object) -> std::shared_ptr<Object> {
  om_manager_.register_manager(&inter_object_manager_);
  inter_object_manager_.do_dispose_request();
  auto objptr = std::shared_ptr<Object>(object);
  inter_object_manager_.alive_object_map_.emplace(object->id(), objptr);
  inter_object_manager_.alive_object_count_ += 1;
  return objptr;
}
/**
 * 销毁对象.
 * 
 * \param id 对象ID
 * \param tid 线程ID
 * \return true或false
 */
auto ObjectSystem::dispose_object(std::uint64_t id, std::thread::id tid)
    -> bool {
  if (tid != inter_object_manager_.tid_) {
    // 多线程对象释放
    return om_manager_.send_dispose_request(id, tid);
  }
  auto it = inter_object_manager_.alive_object_map_.find(id);
  if (it == inter_object_manager_.alive_object_map_.end()) {
    // 所有者线程内无法找到对象
    return false;
  }
  inter_object_manager_.alive_object_map_.erase(it);
  inter_object_manager_.alive_object_count_ -= 1;
  inter_object_manager_.dispose_object_count_ += 1;
  inter_object_manager_.do_dispose_request();
  return true;
}
/**
 * 获取对象.
 * 
 * \param id 对象ID
 * \return 对象的共享指针
 */
auto ObjectSystem::get_object(std::uint64_t id) -> std::shared_ptr<Object> {
  auto it = inter_object_manager_.alive_object_map_.find(id);
  if (it == inter_object_manager_.alive_object_map_.end()) {
    return std::shared_ptr<Object>();
  }
  return it->second;
}
/**
 * 生成一个新的对象ID.
 * 
 * \return 新的对象ID
 */
auto ObjectSystem::new_id() -> std::uint64_t {
  static std::atomic_uint64_t id(1);
  return id++;
}

#ifdef OBJECT_SYSTEM_DEBUG
Object::Object(const std::type_info &type_info, std::thread::id tid,
               const std::string &file, int line)
    : type_info_(type_info), tid_(tid), file_(file), line_(line) {
  id_ = ObjectSystem::new_id();
}
#else
Object::Object(const std::type_info &type_info, std::thread::id tid)
    : type_info_(type_info), tid_(tid) {
  id_ = ObjectSystem::new_id();
}
#endif

Object::~Object() {}

auto Object::dispose() -> bool {
  if (lifecycle_state_ != ObjectState::state_alive) {
    return false;
  }
  lifecycle_state_ = ObjectState::state_dispose;
  return ObjectSystem::dispose_object(id_, tid_);
}

auto Object::is_alive() -> bool {
  return (lifecycle_state_ == ObjectState::state_alive);
}

auto Object::id() -> std::uint64_t { return id_; }

auto Object::thread_id() -> std::thread::id { return tid_; }

void Object::set_thread_mode(ThreadMode thread_mode) {
  thread_mode_ = thread_mode;
}

Object::ThreadMode Object::get_thread_mode() const { return thread_mode_; }

#ifdef OBJECT_SYSTEM_DEBUG
auto Object::get_file_name() const -> const std::string & { return file_; }

auto Object::get_line() const -> int { return line_; }

auto Object::type_info() const -> const std::type_info & { return type_info_; }

#else
auto Object::get_file_name() const -> const std::string & {
  static std::string null;
  return null;
}

auto Object::get_line() const -> int { return 0; }
#endif

} // namespace object_system
} // namespace kratos
